package com.xy.server.service;

import com.alibaba.fastjson.JSON;
import com.xy.server.database.FaceDBService;
import com.xy.server.database.FaceMapper;
import com.xy.server.entity.CaptureProfile;
import com.xy.server.entity.MosaicTemplate;
import com.xy.server.entity.Profile;
import com.xy.server.util.ImageUtil;
import com.xy.server.util.ServerUtil;
import com.xy.server.util.TimeUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.awt.image.RescaleOp;
import java.io.File;
import java.util.*;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.imageio.ImageIO;

/**
 * 图像处理类.
 *
 * @author nagsh
 *
 */
@Service("mosaicService")
public class MosaicService {

    String openUrl; // 原始图片打开路径
    String saveUrl; // 新图保存路径
    String saveName; // 新图名称
    String suffix; // 新图类型 仅仅支持gif,jpg,png

    @Autowired
    FaceService faceService;

    @Autowired
    FaceMapper faceMapper;


    BufferedImage blankRectMosaicBuffer;

    public MosaicService(){


    }
    public MosaicService(String openUrl, String saveUrl, String saveName,
                     String suffix) throws Exception {
        this.openUrl = openUrl;
        this.saveName = saveName;
        this.saveUrl = saveUrl;
        this.suffix = suffix;




    }

    public void init() throws Exception {


        File blankRectMosaicFile = new File(ServerUtil.ResImgPath + "mosaic_template_blank_rect.png");
        blankRectMosaicBuffer = ImageIO.read(blankRectMosaicFile); // 读取该图片
    }
    /**
     * 图片缩放.
     *
     * @param width
     *            须要的宽度
     * @param height
     *            须要的高度
     * @throws Exception
     */
    public void zoom(int width, int height) throws Exception {
        double sx = 0.0;
        double sy = 0.0;

        File file = new File(openUrl);
        if (!file.isFile()) {
            throw new Exception("ImageDeal>>>" + file + " 不是一个图片文件!");
        }
        BufferedImage bi = ImageIO.read(file); // 读取该图片
        // 计算x轴y轴缩放比例--如需等比例缩放，在调用之前确保參数width和height是等比例变化的
        sx = (double) width / bi.getWidth();
        sy = (double) height / bi.getHeight();

        AffineTransformOp op = new AffineTransformOp(
                AffineTransform.getScaleInstance(sx, sy), null);
        File sf = new File(saveUrl, saveName + "." + suffix);
        Image zoomImage = op.filter(bi, null);
        try {
            ImageIO.write((BufferedImage) zoomImage, suffix, sf); // 保存图片
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 旋转
     *
     * @param degree
     *            旋转角度
     * @throws Exception
     */
    public void spin(int degree) throws Exception {
        int swidth = 0; // 旋转后的宽度
        int sheight = 0; // 旋转后的高度
        int x; // 原点横坐标
        int y; // 原点纵坐标

        File file = new File(openUrl);
        if (!file.isFile()) {
            throw new Exception("ImageDeal>>>" + file + " 不是一个图片文件!");
        }
        BufferedImage bi = ImageIO.read(file); // 读取该图片
        // 处理角度--确定旋转弧度
        degree = degree % 360;
        if (degree < 0) {
            degree = 360 + degree;// 将角度转换到0-360度之间
        }
        double theta = Math.toRadians(degree);// 将角度转为弧度

        // 确定旋转后的宽和高
        if (degree == 180 || degree == 0 || degree == 360) {
            swidth = bi.getWidth();
            sheight = bi.getHeight();
        } else if (degree == 90 || degree == 270) {
            sheight = bi.getWidth();
            swidth = bi.getHeight();
        } else {
            swidth = (int) (Math.sqrt(bi.getWidth() * bi.getWidth()
                    + bi.getHeight() * bi.getHeight()));
            sheight = (int) (Math.sqrt(bi.getWidth() * bi.getWidth()
                    + bi.getHeight() * bi.getHeight()));
        }

        x = (swidth / 2) - (bi.getWidth() / 2);// 确定原点坐标
        y = (sheight / 2) - (bi.getHeight() / 2);

        BufferedImage spinImage = new BufferedImage(swidth, sheight,
                bi.getType());
        // 设置图片背景颜色
        Graphics2D gs = (Graphics2D) spinImage.getGraphics();
        gs.setColor(Color.white);
        gs.fillRect(0, 0, swidth, sheight);// 以给定颜色绘制旋转后图片的背景

        AffineTransform at = new AffineTransform();
        at.rotate(theta, swidth / 2, sheight / 2);// 旋转图象
        at.translate(x, y);
        AffineTransformOp op = new AffineTransformOp(at,
                AffineTransformOp.TYPE_BICUBIC);
        spinImage = op.filter(bi, spinImage);
        File sf = new File(saveUrl, saveName + "." + suffix);
        ImageIO.write(spinImage, suffix, sf); // 保存图片

    }


    public boolean mosaicTemplate() throws Exception {

        int size = 25;//FaceDBService.getDicValueByName("mosaic_icon_size");

        faceMapper.clearMosaicTemplate();

        File file = new File(ServerUtil.MosaicTemplatePath);
        if (!file.isFile()) {
            throw new Exception("ImageDeal>>>" + file + " 不是一个图片文件!");
        }
        BufferedImage bi = ImageIO.read(file); // 读取该图片

        if (bi.getWidth() < size || bi.getHeight() < size || size <= 0) { // 马赛克格尺寸太大或太小
            return false;
        }


        int xcount = 0; // 方向绘制个数
        int ycount = 0; // y方向绘制个数
        if (bi.getWidth() % size == 0) {
            xcount = bi.getWidth() / size;
        } else {
            xcount = bi.getWidth() / size + 1;
        }
        if (bi.getHeight() % size == 0) {
            ycount = bi.getHeight() / size;
        } else {
            ycount = bi.getHeight() / size + 1;
        }
        int x = 0;   //坐标
        int y = 0;

        int iconCount = 0;
        int iconTotalCount = 0;

        // 绘制马赛克(绘制矩形并填充颜色)
        for (int i = 0; i < xcount; i++) {
            for (int j = 0; j < ycount; j++) {
                System.out.println(i + "/" + xcount + "," + j + "/" + ycount);
                //马赛克矩形格大小
                int mwidth = size;
                int mheight = size;
                if(i==xcount-1){   //横向最后一个比較特殊，可能不够一个size
                    mwidth = bi.getWidth()-x;
                }
                if(j == ycount-1){  //同理
                    mheight =bi.getHeight()-y;
                }
                // 矩形颜色取中心像素点RGB值
                int centerX = x;
                int centerY = y;
                if (mwidth % 2 == 0) {
                    centerX += mwidth / 2;
                } else {
                    centerX += (mwidth - 1) / 2;
                }
                if (mheight % 2 == 0) {
                    centerY += mheight / 2;
                } else {
                    centerY += (mheight - 1) / 2;
                }
                Color color = new Color(bi.getRGB(centerX, centerY));
                //gs.setColor(color);

                int red_count = 0;
                int green_count = 0;
                int blue_count = 0;
                int pixel_count = 0;

                for (int ty = 0; ty < mheight; ty++)
                {
                    for (int tx = 0; tx < mwidth; tx++)
                    {
                        Color c = new Color(bi.getRGB(tx+x, ty+y));

                        pixel_count++;
                        red_count += c.getRed();
                        green_count += c.getGreen();
                        blue_count += c.getBlue();
                    }
                }

                Color averageColor = new Color(red_count*1.0f / pixel_count/255,
                        green_count*1.0f / pixel_count/255,
                        blue_count*1.0f / pixel_count/255);

                iconTotalCount++;

                if(averageColor.getRed() == 0 && averageColor.getBlue() == 0 && averageColor.getGreen() == 0){

                }
                else {

                    iconCount++;

                    faceMapper.addMosaicTemplate(x,y,mwidth,mheight,red_count,green_count,blue_count,pixel_count,System.currentTimeMillis());

                }

                y = y + size;// 计算下一个矩形的y坐标
            }
            y = 0;// 还原y坐标
            x = x + size;// 计算x坐标
        }

        System.out.println("icon total count " + iconTotalCount);
        System.out.println("icon count " + iconCount);

        faceMapper.updateDicValue("mosaic_icon_total_count",String.valueOf(iconTotalCount));
        faceMapper.updateDicValue("mosaic_icon_count",String.valueOf(iconCount));
        return true;
    }


    public class ProfileRunnable implements Runnable{

        String threadName;
        int startIndex;
        int count;
        List<Profile> profileList;

        ProfileRunnable(String threadName,int startIndex,int count,List<Profile> profileList) {
            this.startIndex = startIndex;
            this.count = count;
            this.threadName = threadName;
            this.profileList = profileList;
        }

        @Override
        public void run() {
            int length = startIndex + count > mosaicTemplateList.size() ?  mosaicTemplateList.size() :  startIndex + count;

            for(int i = startIndex ; i < length ; ++i) {
                Profile profile = profileList.get((int) (Math.random() * 100) % profileList.size());

                MosaicTemplate mosaicTemplate = mosaicTemplateList.get(i);

                Color averageColor = new Color(mosaicTemplate.getRed_count() * 1.0f / mosaicTemplate.getPixel_count() / 255,
                        mosaicTemplate.getGreen_count() * 1.0f / mosaicTemplate.getPixel_count() / 255,
                        mosaicTemplate.getBlue_count() * 1.0f / mosaicTemplate.getPixel_count() / 255);


                int ob = (int) ((0.2125 * averageColor.getRed()) + (0.7154 * averageColor.getGreen()) + (0.072 * averageColor.getBlue()));

                mosaicTemplate.setOb(ob);

                float nowBri = 10.0f + (ob - profile.getAverageBrightness()) * 1.0f / ob * 200;

                int bri  = (int) nowBri/10*10;

                if(!profile.getBufferedMap().containsKey(bri)) {

                    BufferedImage profileFilter = new BufferedImage(profile.getProfile().getWidth(),
                            profile.getProfile().getHeight(),
                            BufferedImage.TYPE_INT_RGB);

                    RescaleOp rescale = new RescaleOp(1.0f, bri, null);
                    rescale.filter(profile.getProfile(), profileFilter);

                    //black and white
                    ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
                    ColorConvertOp op = new ColorConvertOp(cs, null);
                    profileFilter = op.filter(profileFilter, null);

                    profile.getBufferedMap().put(bri,profileFilter);
                }

                mosaicTemplate.setProfileFilter(profile.getBufferedMap().get(bri));

                //System.out.println(threadName +" " + i);
            }

            latch.countDown();
        }
    }
    static final int threadCount = 5;
    private  List<MosaicTemplate> mosaicTemplateList;
    CountDownLatch latch = new CountDownLatch(threadCount);

    private String lastMosaicFilename;

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(threadCount);


    /**
     * 马赛克化.
     * @return
     * @throws Exception
     */
    public Map<String,Object> mosaic(Map<String,Object> result) throws Exception {

        int size = 25;


        File file = new File(ServerUtil.MosaicTemplatePath);
        if (!file.isFile()) {
            throw new Exception("ImageDeal>>>" + file + " 不是一个图片文件!");
        }
        BufferedImage bi = ImageIO.read(file); // 读取该图片


        if (bi.getWidth() < size || bi.getHeight() < size || size <= 0) { // 马赛克格尺寸太大或太小
            return null;
        }


        if(mosaicTemplateList == null) {
            mosaicTemplateList = faceMapper.getMosaicTemplateList();

            for(MosaicTemplate mosaicTemplate:mosaicTemplateList){
                Color averageColor = new Color(mosaicTemplate.getRed_count() * 1.0f / mosaicTemplate.getPixel_count() / 255,
                        mosaicTemplate.getGreen_count() * 1.0f / mosaicTemplate.getPixel_count() / 255,
                        mosaicTemplate.getBlue_count() * 1.0f / mosaicTemplate.getPixel_count() / 255);


                int ob = (int) ((0.2125 * averageColor.getRed()) + (0.7154 * averageColor.getGreen()) + (0.072 * averageColor.getBlue()));
                mosaicTemplate.setOb(ob);
            }
        }

        String lastMosaicFilename = faceMapper.getDicStringByName("last_mosaic_image");
        if(lastMosaicFilename == null){
            lastMosaicFilename = "mosaic_template_first.jpg";
        }

        System.out.println("lastMosaicFilename before " + lastMosaicFilename);

        File lastMosaicFile = new File(ServerUtil.ResPath + lastMosaicFilename);
        if (!lastMosaicFile.isFile()) {
            throw new Exception("Image >>>" + lastMosaicFile + " 不是一个图片文件!");
        }
        BufferedImage lastMosaicBuffer = ImageIO.read(lastMosaicFile); // 读取该图片



        String originFileName = result.get("origin_file_name").toString();

        List faces = (java.util.List<Object>)result.get("faces");

        // 绘制马赛克(绘制矩形并填充颜色)
        Graphics gs = lastMosaicBuffer.getGraphics();

        BufferedImage blankMosaicBuffer;
        File blankMosaicFile = new File(ServerUtil.ResImgPath + "mosaic_template_blank.png");
        blankMosaicBuffer = ImageIO.read(blankMosaicFile); // 读取该图片

        Graphics gsBlank = blankMosaicBuffer.getGraphics();

        for(int i = 0; i < faces.size(); ++i) {
            Map<String, Object> face = (Map<String, Object>) faces.get(i);

            if (!face.containsKey("attributes")) {
                continue;
            }

            Map<String, Object> attributes = (Map<String, Object>) face.get("attributes");

            Map<String, Object> rectangle = (Map<String, Object>) face.get("face_rectangle");


            int redCount = 0;
            int greenCount = 0;
            int blueCount = 0;
            int pixelCount = 0;

            String profileFilename = face.get("profile_filename").toString();

            BufferedImage icon = ImageIO.read(new File(ServerUtil.ResPath + "/" + profileFilename));

            for (int iy = 0; iy < icon.getHeight(); iy++)
            {
                for (int ix = 0; ix < icon.getWidth(); ix++)
                {
                    Color c = new Color(icon.getRGB(ix, iy));

                    pixelCount++;
                    redCount += c.getRed();
                    greenCount += c.getGreen();
                    blueCount += c.getBlue();
                    // does alpha matter?
                }
            }


            Map<String,Object> emotion = (Map<String,Object>)attributes.get("emotion");

            String expression = faceService.getExpression(emotion);

            Profile profile = increaseEmotion(originFileName,profileFilename,expression,redCount,greenCount ,blueCount,pixelCount);

            for(int k = 0 ;k < 1 ; ++k) {

                Random random1 = new Random();

                MosaicTemplate mosaicTemplate = mosaicTemplateList.get(Math.abs(random1.nextInt()) % mosaicTemplateList.size());

                BufferedImage bufferedImage = getProfileBufferDependOnMosaicTemplate(mosaicTemplate, profile);

                gs.drawImage(bufferedImage, mosaicTemplate.getX(), mosaicTemplate.getY(), mosaicTemplate.getWidth(), mosaicTemplate.getHeight(), null);

                int x = mosaicTemplate.getY();
                int y = blankMosaicBuffer.getHeight()- mosaicTemplate.getX() - mosaicTemplate.getWidth();
                int width = mosaicTemplate.getHeight();
                int height = mosaicTemplate.getWidth();

                gsBlank.drawImage(blankRectMosaicBuffer, x, y, width, height, null);

                face.put("x",x);
                face.put("y",y);
                face.put("width",width);
                face.put("height",height);
            }

        }

        gs.dispose();
        gsBlank.dispose();


        String mosaicFileName = originFileName.substring(0,originFileName.lastIndexOf("."));
        mosaicFileName += "_mosaic";
        String ext = originFileName.substring(originFileName.lastIndexOf("."));

        ImageIO.write(lastMosaicBuffer, "jpg", new File(ServerUtil.ResPath + mosaicFileName + ext));

        lastMosaicFilename =  mosaicFileName + ext;

        faceMapper.updateDicValue("last_mosaic_image",lastMosaicFilename);
        System.out.println("lastMosaicFilename after " + lastMosaicFilename);

        String rotateFilename = ImageUtil.rotatePhoto(ServerUtil.ResPath ,lastMosaicFilename,270);
        System.out.println("rotateMosaicFilename after " + rotateFilename);


        mosaicFileName += "_blank";
        ext = ".png";

        ImageIO.write(blankMosaicBuffer, "png", new File(ServerUtil.ResPath + mosaicFileName + ext));

        Map<String,Object> map = new HashMap<>();
        map.put("mosaic",rotateFilename);
        map.put("blank",mosaicFileName + ext);
        map.put("faces",result.get("faces"));

        return map;
    }

    private BufferedImage getProfileBufferDependOnMosaicTemplate(MosaicTemplate mosaicTemplate,Profile profile){


        float nowBri = 10.0f + (mosaicTemplate.getOb() - profile.getAverageBrightness()) * 1.0f / mosaicTemplate.getOb() * 200;

        int bri  = (int) nowBri/10*10;

        if(!profile.getBufferedMap().containsKey(bri)) {
            BufferedImage profileFilter = new BufferedImage(profile.getProfile().getWidth(),
                    profile.getProfile().getHeight(),
                    BufferedImage.TYPE_INT_RGB);

            RescaleOp rescale = new RescaleOp(1.0f, bri, null);
            rescale.filter(profile.getProfile(), profileFilter);

            //black and white
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
            ColorConvertOp op = new ColorConvertOp(cs, null);
            profileFilter = op.filter(profileFilter, null);
            profile.getBufferedMap().put(bri,profileFilter);
        }

        return profile.getBufferedMap().get(bri);
    }


    private Profile increaseEmotion(
            String originFileName,String profileFileName, String emotion,
            int red_count,int green_count , int blue_count , int pixel_count
    ) throws Exception{
        int curVal = Integer.valueOf(faceService.getStatMap().get(emotion).toString());
        faceService.getStatMap().put(emotion, curVal + 1);
        faceMapper.increaseDicValue(emotion);

        faceMapper.addProfile(originFileName,profileFileName,emotion,red_count,green_count ,blue_count,pixel_count,System.currentTimeMillis());

        File file = new File(ServerUtil.ResPath + profileFileName);

        Profile profile = new Profile(
                file,
                originFileName,
                emotion,
                red_count,
                green_count,
                blue_count,
                pixel_count,
                System.currentTimeMillis()
        );

        return profile;
    }



    public static void main(String[] args) throws Exception {
//        MosaicService imageDeal = new MosaicService(
//                //"/Users/agan/Downloads/1.jpg",
//                //"/Users/agan/百度云同步盘/XY/photos/mmexport1501329096602.jpg",
////                "/Users/agan/百度云同步盘/XY/photos/mmexport1501329211384-3.jpg",
////                "/Users/agan/百度云同步盘/XY/photos/mmexport1501329211384-2.jpg",
//                "/Users/agan/Downloads/WechatIMG2924-2.jpg",
//                "/Users/agan/Downloads/",
//                "xy14",
//                "jpg"
//        );
        // 測试缩放
        /* imageDeal.zoom(200, 300); */
        // 測试旋转
        /* imageDeal.spin(90); */
        //測试马赛克
//        imageDeal.mosaic(25);

        float ga = -23232.32f;

        System.out.println((int)ga/100);

        System.out.println(Math.random());

        Random random1 = new Random();

        System.out.println(random1.nextInt());
        System.out.println(Math.abs(random1.nextInt())%10);
    }

}